package server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;


/**
 * 
 * Server-side handler for each client
 * Runs as its own thread 
 *
 */
public class ClientController implements Runnable{

	private Socket socket;
	private String username;
	String hostName;
	int port;
	BufferedReader reader;
	PrintWriter writer;
	private boolean loggedIn;

	/**
	 * Constructor
	 * @param reader
	 * @param writer
	 */
	public ClientController(BufferedReader reader, PrintWriter writer){
		this("localhost", 4444, reader, writer);		
	}

	/**
	 * Constructor
	 * @param socket
	 * @param reader
	 * @param writer
	 */
	public ClientController(Socket socket, BufferedReader reader, PrintWriter writer) {
		this.socket = socket;
		this.reader = reader;
		this.writer = writer;
		System.out.println("in cc constructor!");
	}
	
	/**
	 * Constructor
	 * @param hostName
	 * @param port
	 * @param reader
	 * @param writer
	 */
	public ClientController(String hostName, int port, BufferedReader reader, PrintWriter writer){
		this.hostName = hostName;
		this.port = port;
		this.writer = writer;
		this.reader = reader;
		this.loggedIn = false;
	}

	/**
	 * Writes a line to its own writer
	 * @param input
	 */
	public void writeLine(String output) {
		System.out.println(username + " clientcontroller writeline " + output + " out to socket");
		writer.println(output);
	}

	/**
	 * Reads a line from its own reader
	 * @return String
	 * @throws IOException
	 */
	public String readLine() throws IOException {
		return reader.readLine();
	}

	/**
	 * Determines if a reader has text to be read
	 * @return boolean
	 * @throws IOException
	 */
	public boolean canRead() throws IOException {
		return reader.ready();
	}

	/**
	 * Closes thread
	 * @throws IOException
	 */
	public void close() throws IOException {
		writer.close();
		reader.close();
		socket.close();
	}

	/**
	 * Runs thread
	 */
	public void run() {
System.out.println("client controller running");
		try {
			writer.flush();	
			// Read the first line.
			String line = null;

			while(!reader.ready()){
				//System.out.println("in reader ready??");
			}
			line = reader.readLine();
			while (line != null) { 
				System.out.println(username + " loggedIn: " + loggedIn);
				// actions for a user that is not yet part of the network
				if(!loggedIn)
				{
					
					// login commands
					if(line.startsWith("login")) 
					{
						System.out.println("In clientcontroller: line starts with login");
						String details = line.substring(6, line.length()-1);
						String[] params = details.split(",");
						String outcome = loginUser(params);
						loggedIn = true;
						System.out.println("loggedIn set to " + loggedIn);
						System.out.println("writing to sockets to client this outcome " + outcome);
						this.writeLine(outcome);
					}
					// invalid commands
					else
					{
						System.out.println(username + " invalid command! " + line );
						this.writeLine("Invalid Command!");
					}
				}
				// all other commands get sent to the server manager
				else 
				{
					if (line.startsWith("logOut")) 
					{
						System.out.println("logging out in controller" );
						String details = line.substring(7, line.length()-1);
						String[] params = details.split(",");
						String username = params[0];
						String outcome = logOut(params);	
						loggedIn = false;
						Server.clientWriters.get(username).println(outcome);
						Server.clientWriters.remove(username);
					}
					
					System.out.println(username + " cc: adding to command queue this: " + line);
					ServerManager.commandQueue.add(line);
				}
				// Read next line.
				
				System.out.println(username + " cc is reading next line");
				line = reader.readLine();
				System.out.println("read line: " + line);
			}
			// Close streams, socket and socket server.
			writer.println("Closing connection... ");
			writer.flush();
			reader.close();
			writer.close();

		} catch (IOException e) {
			
			System.out.println("in clientcontroller exception!");
			System.out.println("I/O error: " + e.getMessage());
			loggedIn = false;
			
			Server.userMap.remove(username);
			System.out.println("in exception, logged out " + username);
		}
		
		Server.userMap.remove(username);
		loggedIn = false;
		System.out.println("logged out outside loop " + username);
		System.out.println("Connection closed");
		
	}

	/**
	 * Gets the username of the client associated with this controller
	 * @param username
	 */
	public void setUsername(String username) {
		this.username = username;
	}

	/**
	 * Sets the username of the client associate with thhis controller
	 * @return
	 */
	public String getUsername() {
		return username;
	}


	/**
	 * Logs in an already-registed user
	 * @param params : String[]
	 * @return String : reflects the outcome of the method
	 */
	public String loginUser(String[] params) {
		System.out.println("in clientcontroller: loginUser function");
		username = params[0];
		System.out.println("trying to log in " + username);
		if (!Server.userMap.containsKey(username))
		{
			System.out.println("userMap doesn't contain "+username);
			User user = new User(username);
			Server.userMap.put(username, user);
			Server.clientWriters.put(username, writer);
		
			Server.chatroom.addUser(user);
			System.out.println("added " + username);
			System.out.println("userMap size now" + Server.userMap.size());
			System.out.println("clientWriters size " + Server.clientWriters.size());
			
			return Message.loginSuccessful(username);
		}
		else
		{
			return Message.userAlreadyExists();
		}
	
		
	}

	

	/**
	 * Logs out an online user
	 * @param params : String[]
	 * @return String : reflects the outcome of the method
	 */
	public String logOut(String[] params) 
	{
		username = params[0];
		if (!Server.userMap.containsKey(username)){
			System.out.println(username + "fukda");
			username = "";
			return Message.logOutFail();
		} else {
			
			Server.userMap.remove(username);
			System.out.println("usermap size " + Server.userMap.size());
			System.out.println("clientwriters size " + Server.clientWriters.size());
			
			username = "";
			return Message.logOutSuccessful();
		}
	}
}




